﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Luna;

namespace TextDataExtractor.DEML {

	public class InclusionPattern : AbstractPattern {
		private AbstractPattern pattern;
		private List<AbstractPattern> matchedPatterns = new List<AbstractPattern>();
		private int maxOccur;
		private DemlRegistry registry;

		public InclusionPattern() {
			MinOccur = 1;
			MaxOccur = 1;
		}

		public InclusionPattern(AbstractPattern pattern, int minOccur, int maxOccur) {
			this.pattern = pattern;
			MinOccur = minOccur;
			MaxOccur = maxOccur;
		}

		public override string FullName {
			get {
				return Pattern != null ? Pattern.FullName : base.FullName;
			}
		}

		public int MinOccur { get; set; }

		public int MaxOccur { get { return Math.Max(MinOccur, maxOccur); } set { maxOccur = value; } }

		public AbstractPattern Pattern {
			get { 
				return pattern != null ? pattern : (pattern = registry.findPattern(getArgument("name")).safeClone<AbstractPattern>()); 
			}
			set { pattern = value; }
		}

		public override void loadFromXml(System.Xml.XmlNode node, DemlRegistry registry) {
			base.loadFromXml(node, registry);
			MinOccur = getArgument("minoccur").toInt(1);
			MaxOccur = getArgument("maxoccur").Equals("n") ? int.MaxValue : getArgument("maxoccur").toInt(1);
			Name = "";
			this.registry = registry;
		}

		public override int match(string input) {
			int ires;
			matchedPatterns.Clear();
			int result = 0;
			if (Pattern != null) {
				StartIndex = -1;
				EndIndex = 0;
				do {
					AbstractPattern p = MaxOccur > 1 ? (AbstractPattern)pattern.Clone() : pattern;
					if ((ires = p.match(input)) > 0) {
						result += ires;
						StartIndex = StartIndex > -1 ? StartIndex : p.StartIndex;
						EndIndex += p.EndIndex;
						matchedPatterns.Add(p);
						if (MaxOccur > 1) 
							p.Name += string.Format(": {0}", matchedPatterns.Count);
						input = p.EndIndex + 1 < input.Length ? input.Substring(p.EndIndex + 1) : string.Empty;
					}
				
				} while (matchedPatterns.Count < MaxOccur && ires > 0 && input.isNotNullAndEmpty());
			}
			IsSuccess = matchedPatterns.Count >= MinOccur;
			return IsSuccess ? result : 0;
		}

		public override void CopyTo(DemlElement target) {
			base.CopyTo(target);
			InclusionPattern p = (InclusionPattern)target;
			p.pattern = Pattern != null ? (AbstractPattern)Pattern.Clone() : null;
			p.maxOccur = maxOccur;
			p.registry = registry;
		}

		protected override void doExtraction(ExecutionContext context) {
			foreach (var item in matchedPatterns)
				item.performExtraction(context);
		}

		public override IEnumerable<AbstractPattern> getMatchedPatterns(Predicate<AbstractPattern> pred) {
			if (IsSuccess)
				if (pred(pattern))
					foreach (AbstractPattern p in matchedPatterns)
						yield return p;
		}

		public override string getMatchedPatternName(int indent) {
			if (IsSuccess) {
				StringBuilder b = new StringBuilder();
				for (int i = 0; i < matchedPatterns.Count; i++) {
					if (i > 0) b.AppendLine();
					b.Append(matchedPatterns[i].getMatchedPatternName(indent));
					// b.AppendFormat(": {0}", i + 1);
				}
				return b.ToString();
			}
			return String.Empty;
		}
	}
}
